package cn.growthgate.fgo.web;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;

import javax.validation.constraints.NotNull;

import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.baomidou.mybatisplus.plugins.Page;

import cn.growthgate.fgo.common.Constants;
import cn.growthgate.fgo.common.base.BaseVo;
import cn.growthgate.fgo.entity.Class;
import cn.growthgate.fgo.entity.Cv;
import cn.growthgate.fgo.entity.Image;
import cn.growthgate.fgo.entity.Item;
import cn.growthgate.fgo.entity.Painter;
import cn.growthgate.fgo.entity.Servant;
import cn.growthgate.fgo.entity.ServantBond;
import cn.growthgate.fgo.entity.ServantCv;
import cn.growthgate.fgo.entity.ServantItem;
import cn.growthgate.fgo.entity.ServantWhite;
import cn.growthgate.fgo.entity.enums.ServantItemType;
import cn.growthgate.fgo.entity.enums.ServantPropB;
import cn.growthgate.fgo.entity.enums.ServantTrait;
import cn.growthgate.fgo.service.IClassService;
import cn.growthgate.fgo.service.ICvService;
import cn.growthgate.fgo.service.IImageService;
import cn.growthgate.fgo.service.IItemService;
import cn.growthgate.fgo.service.IPainterService;
import cn.growthgate.fgo.service.IServantBondService;
import cn.growthgate.fgo.service.IServantCvService;
import cn.growthgate.fgo.service.IServantItemService;
import cn.growthgate.fgo.service.IServantService;
import cn.growthgate.fgo.service.IServantTraitsService;
import cn.growthgate.fgo.service.IServantWhiteService;
import cn.growthgate.fgo.util.StringUtils;
import cn.growthgate.fgo.web.result.JsonResult;
import cn.growthgate.fgo.web.result.TableResult;

/**
 * <p>
 * 用户表 前端控制器
 * </p>
 *
 * @author GrowthGate
 * @since 2019-01-20
 */
@Controller
@RequestMapping("/servant")
public class ServantController {

	@Autowired
	private IServantService servantService;

	@Autowired
	private IClassService classService;

	@Autowired
	private ICvService cvService;

	@Autowired
	private IPainterService painterService;

	@Autowired
	private IServantCvService servantCvService;

	@Autowired
	private IServantBondService servantBondService;

	@Autowired
	private IImageService imageService;

	@Autowired
	private IServantWhiteService servantWhiteService;
	
	@Autowired
	private IServantTraitsService servantTraitsService;

	@Autowired
	private IServantItemService servantItemService;

	@Autowired
	private IItemService itemService;

	@RequestMapping("/list")
	@RequiresRoles(value = {Constants.ROLE_ADMIN}, logical = Logical.OR)
	public String list() {
		return "servant/list";
	}

	@ResponseBody
	@RequestMapping("/tableData")
	@RequiresRoles(value = {Constants.ROLE_ADMIN}, logical = Logical.OR)
	public TableResult<Servant> tableData(Servant entity, Integer current, Integer size, String orderByField,
			Boolean isAsc) {
		Wrapper<Servant> wrapper = new EntityWrapper<>();

		if (StringUtils.isNotBlank(entity.getName())) {
			wrapper.andNew().like("name", entity.getName()).or().like("jName", entity.getName()).or()
					.like("eName", entity.getName()).or().like("nickName", entity.getName());
		}

		Page<Servant> page = servantService.selectPage(current, size, orderByField, isAsc, wrapper);
		return new TableResult<Servant>(page);
	}

	@RequestMapping("/form")
	@RequiresRoles(value = {Constants.ROLE_ADMIN}, logical = Logical.OR)
	public ModelAndView form(Long id) {
		Servant entity = servantService.selectById(id);
		List<Class> classes = classService.selectAll();
		List<Cv> cvs = cvService.selectAll();
		List<ServantCv> servantCvs = servantCvService.selectByServantId(id);
		List<Painter> painters = painterService.selectAll();
		Map<Integer, ServantBond> servantBondMap = servantBondService.selectByServantId(id).stream()
				.collect(Collectors.toMap(ServantBond::getLevel, servantBond -> servantBond));
		List<Serializable> traits = servantTraitsService.selectByServantId(id).stream()
				.map(servantTraits -> servantTraits.getTrait().getValue()).collect(Collectors.toList());

		return new ModelAndView("servant/form").addObject("entity", entity).addObject("classes", classes)
				.addObject("cvs", cvs).addObject("servantCvs", servantCvs).addObject("painters", painters)
				.addObject("servantBondMap", servantBondMap).addObject("traits", traits);
	}

	@ResponseBody
	@RequestMapping("/save")
	@RequiresRoles(value = {Constants.ROLE_ADMIN}, logical = Logical.OR)
	public JsonResult save(Servant entity, BindingResult bindingResult, Long[] servantCvId, Long[] cvId,
			String[] remark, ServantTrait[] traits, @RequestParam Map<String, String> map) {
		if (bindingResult.hasErrors()) {
			return JsonResult.fail(bindingResult.getAllErrors().get(0).getDefaultMessage());
		}
		if (entity.getId() != null) {
			// 编辑
			Servant oEntity = servantService.selectById(entity.getId());
			// 更改图片
			changeImage(oEntity.getAvatar(), entity.getAvatar());
		}
		servantService.insertOrUpdate(entity);
		updateImage(entity, entity.getAvatar());

		// 声优
		// 之前的记录id
		List<Long> oScId = servantCvService.selectByServantId(entity.getId()).stream().map(ServantCv::getId)
				.collect(Collectors.toList());
		if (servantCvId != null && cvId != null && remark != null) {
			if (cvId.length > servantCvId.length) {
				// 扩充数组长度
				servantCvId = Arrays.copyOf(servantCvId, cvId.length);
			}
			if (cvId.length > remark.length) {
				// 扩充数组长度
				remark = Arrays.copyOf(remark, cvId.length);
			}
			List<ServantCv> cvs = new ArrayList<>();
			for (int i = 0; i < cvId.length; i++) {
				if (cvId[i] != null) {
					ServantCv servantCv = new ServantCv();
					servantCv.setId(servantCvId[i]);
					servantCv.setServantId(entity.getId());
					servantCv.setCvId(cvId[i]);
					servantCv.setRemark(remark[i]);
					cvs.add(servantCv);
					if (servantCvId[i] != null) {
						oScId.remove(servantCvId[i]);
					}
				}
			}
			servantCvService.insertOrUpdateBatch(cvs);
			// 删除被删掉的记录
			servantCvService.deleteBatchIds(oScId);
		}
		// 从者羁绊
		for (Entry<String, String> entry : map.entrySet()) {
			if (entry.getKey().startsWith("bond") && StringUtils.isNotBlank(entry.getValue())) {
				// 获取羁绊值
				int level = Integer.valueOf(entry.getKey().replaceFirst("bond", ""));
				int value = Integer.valueOf(entry.getValue());

				ServantBond servantBond = new ServantBond();
				servantBond.setServantId(entity.getId());
				servantBond.setLevel(level);
				servantBond.setValue(value);

				servantBondService.insertOrUpdate(servantBond);
			}
		}
		// 特性
		servantTraitsService.saveTraits(entity.getId(), traits);

		return JsonResult.ok();
	}

	private void changeImage(String oUuid, String uuid) {
		if (oUuid != null && !oUuid.equals(uuid)) {
			imageService.deleteByUUID(oUuid);
		}
	}

	private void updateImage(Servant entity, String uuid) {
		if (StringUtils.isNotBlank(uuid)) {
			Image image = imageService.getByUUID(uuid);
			image.setEntityId(entity.getId());
			image.setEntityName(entity.getClass().getSimpleName());
			imageService.updateById(image);
		}
	}

	@ResponseBody
	@RequestMapping("/delete")
	@RequiresRoles(value = {Constants.ROLE_ADMIN}, logical = Logical.OR)
	public JsonResult delete(Long[] ids) {
		if (servantService.deleteBatchIds(Arrays.asList(ids))) {
			imageService.deleteByEntity(Servant.class.getSimpleName(), ids);
			return JsonResult.ok("删除成功");
		} else {
			return JsonResult.fail("删除失败");
		}
	}

	@RequestMapping("/show")
	public ModelAndView show() {
		List<Class> classes = classService.selectAll();
		List<Map<String, Object>> stars = new ArrayList<>();
		for (int i = 0; i <= 5; i++) {
			Map<String, Object> map = new HashMap<>();
			map.put("value", i);
			map.put("desc", "★ " + i);
			stars.add(map);
		}
		List<Cv> cvs = cvService.selectAll();
		List<Painter> painters = painterService.selectAll();

		return new ModelAndView("servant/show").addObject("classes", classes).addObject("stars", stars)
				.addObject("cvs", cvs).addObject("painters", painters);
	}

	@ResponseBody
	@RequestMapping("/showTableData")
	public TableResult<BaseVo<Servant>> showTableData(Servant entity, Long cvId, ServantTrait trait, Integer current,
			Integer size, String orderByField, Boolean isAsc) {
		Wrapper<Servant> wrapper = new EntityWrapper<>();

		// 防止只有order by的情况下sql语句报错
		wrapper.where("1 = 1");
		if (entity.getClassId() != null) {
			wrapper.eq("s.classId", entity.getClassId());
		}
		if (entity.getStar() != null) {
			wrapper.eq("s.star", entity.getStar());
		}
		if (entity.getCost() != null) {
			wrapper.eq("s.cost", entity.getCost());
		}
		if (entity.getFaction() != null) {
			wrapper.eq("s.faction", entity.getFaction());
		}
		if (entity.getGet() != null) {
			wrapper.like("s.get", entity.getGet());
		}
		if (entity.getNpColorCard() != null) {
			wrapper.eq("s.npColorCard", entity.getNpColorCard());
		}
		if (entity.getNpType() != null) {
			wrapper.eq("s.npType", entity.getNpType());
		}
		if (entity.getCards() != null) {
			wrapper.eq("s.cards", entity.getCards());
		}
		if (entity.getSex() != null) {
			wrapper.eq("s.sex", entity.getSex());
		}
		if (entity.getPropA() != null) {
			wrapper.eq("s.propA", entity.getPropA());
		}
		if (entity.getPropB() != null) {
			if (entity.getPropB() == ServantPropB.GOOD || entity.getPropB() == ServantPropB.EVIL) {
				// 允许同时搜索复合属性的从者
				wrapper.in("s.propB", Arrays.asList(entity.getPropB(), ServantPropB.GOOD_EVIL));
			} else {
				wrapper.eq("s.propB", entity.getPropB());
			}
		}
		if (trait != null) {
			wrapper.eq("st.trait", trait);
		}
		if (cvId != null) {
			wrapper.eq("sc.cvId", cvId);
		}
		if (entity.getPainterId() != null) {
			wrapper.eq("s.painterId", entity.getPainterId());
		}
		if (StringUtils.isNotBlank(entity.getName())) {
			wrapper.andNew().like("s.name", entity.getName()).or().like("s.jName", entity.getName()).or()
					.like("s.eName", entity.getName()).or().like("s.nickName", entity.getName());
		}

		if ("height".equals(orderByField) || "weight".equals(orderByField)) {
			// 字符串转化为数值排序
			orderByField += "+0";
		}

		Page<Servant> page = servantService.selectJoinCv(current, size, orderByField, isAsc, wrapper);
		return new TableResult<BaseVo<Servant>>(servantService.transformVo(page));
	}

	@RequestMapping("/white")
	@RequiresRoles(value = {Constants.ROLE_ADMIN}, logical = Logical.OR)
	public ModelAndView white(Long id) {
		Map<Integer, ServantWhite> servantWhiteMap = servantWhiteService.getServantWhiteMap(id);

		return new ModelAndView("servant/white").addObject("servantWhiteMap", servantWhiteMap);
	}

	@ResponseBody
	@RequestMapping("/whiteSave")
	@RequiresRoles(value = {Constants.ROLE_ADMIN}, logical = Logical.OR)
	public JsonResult whiteSave(Long id, Integer[] hp, Integer[] atk) {
		if (id == null || hp == null || hp.length < 100 || atk == null || atk.length < 100) {
			return JsonResult.fail("参数有误");
		}
		servantWhiteService.saveAll(id, hp, atk);

		return JsonResult.ok();
	}

	@RequestMapping("/item")
	@RequiresRoles(value = {Constants.ROLE_ADMIN}, logical = Logical.OR)
	public ModelAndView item(Long id) {
		List<Item> stageItems = itemService.selectStage();
		List<Item> skillItems = itemService.selectSkill();
		// 组装展示数据
		List<ServantItem> servantItems = servantItemService.selectByServantId(id);
		Map<ServantItemType, Map<Integer, List<ServantItem>>> servantMap = new HashMap<>();
		// 再临阶段1-4
		Map<Integer, List<ServantItem>> stageMap = new HashMap<>();
		for (int i = 1; i <= 4; i++) {
			stageMap.put(i, new ArrayList<>());
		}
		servantMap.put(ServantItemType.STAGE, stageMap);
		Map<Integer, List<ServantItem>> skillMap = new HashMap<>();
		// 技能强化2-10
		for (int i = 2; i <= 10; i++) {
			skillMap.put(i, new ArrayList<>());
		}
		servantMap.put(ServantItemType.SKILL, skillMap);
		servantItems.forEach(
				servantItem -> servantMap.get(servantItem.getType()).get(servantItem.getLevel()).add(servantItem));

		return new ModelAndView("servant/item").addObject("stageItems", stageItems).addObject("skillItems", skillItems)
				.addObject("servantMap", servantMap);
	}

	@ResponseBody
	@RequestMapping("/itemSave")
	@RequiresRoles(value = {Constants.ROLE_ADMIN}, logical = Logical.OR)
	public JsonResult itemSave(@NotNull Long servantId, Long[] ids, Long[] itemIds, ServantItemType[] types,
			Integer[] levels, Integer[] numbers) {
		servantItemService.save(servantId, ids, itemIds, types, levels, numbers);

		return JsonResult.ok();
	}

}
